/*
    File:       Socket.h

    Contains:   Provides a simple, object oriented socket abstraction, also
                hides the details of socket event handling. Sockets can post
                events (such as S_DATA, S_CONNECTIONCLOSED) to Tasks.
                    
    
    
*/

#ifndef __SOCKET_H__
#define __SOCKET_H__

#include <string>

#ifndef __Win32__
#include <netinet/in.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif


#include "OSHeaders.h"
#include "StringParser.h"

class SocketUtils;

class Socket 
{
    public:
        enum
        {
            // Pass this in on socket constructors to specify whether the
            // socket should be non-blocking or blocking
			kBlockingSocketType = 0,
            kNonBlockingSocketType = 1
        };

        enum
        {
            kInvalidFileDesc = -1   //int
        };


		enum

        {

            kMaxNumSockets = 4096   //UInt32

        };

        //Binds the socket to the following address.
        OS_Error		Bind(UInt32 addr, UInt16 port);
        //The same. but in reverse
        void            Unbind();   
        
        void            ReuseAddr();
        void            NoDelay();
        void            KeepAlive();
        void            SetSocketBufSize(UInt32 inNewSize);

	static void Initialize();
	static void Uninitialize();
        //
        // Returns an error if the socket buffer size is too big
        OS_Error        SetSocketRcvBufSize(UInt32 inNewSize);

		OS_Error		SetNonBlocking();
		OS_Error		SetBlocking();

        
        //Send within vtimeout ms
        OS_Error		Send(const char* inData, const UInt32 inLength, UInt32* outLengthSent,UInt32 vTimeOut=0);

	//Peek
	OS_Error		Peek(void *buffer, const UInt32 length, UInt32 *outRecvLenP);
			
        //Read
        //Reads some data.
        OS_Error		Read(void *buffer, const UInt32 length, UInt32 *rcvLen);
        OS_Error		Recv(void *buffer, const UInt32 length, UInt32 *rcvLen) { return Read(buffer,length,rcvLen);}
        
        //WriteV: same as send, but takes an iovec
        OS_Error        WriteV(const struct iovec* iov, const UInt32 numIOvecs, UInt32* outLengthSent,UInt32 vTimeOut=0);
        
        //You can query for the socket's state
        Bool			IsConnected()   { return (Bool) (fState & kConnected); }
        Bool			IsBound()       { return (Bool) (fState & kBound); }
		Bool			IsBlocking() { return m_bIsBlocking; }
        
        //If the socket is bound, you may find out to which addr it is bound
        UInt32			GetLocalAddr()  { return ntohl(fLocalAddr.sin_addr.s_addr); }
        UInt16			GetLocalPort()  { return ntohs(fLocalAddr.sin_port); }

		std::string		GetLocalAddrStr();

		int				GetSocketFD()       { return fFileDesc; }

	private:        
		friend class SocketUtils;
//        StrPtrLen*  GetLocalAddrStr();
//        StrPtrLen*  GetLocalPortStr();
//        StrPtrLen*	GetLocalDNSStr();


    protected:
        //TCPSocket takes an optional task object which will get notified when
        //certain events happen on this socket. Those events are:
        //
        //S_DATA:               Data is currently available on the socket.
        //S_CONNECTIONCLOSING:  Client is closing the connection. No longer necessary
        //                      to call Close or Disconnect, Snd & Rcv will fail.
        
        Socket();
        virtual ~Socket();

        //returns QTSS_NoErr, or appropriate posix error
        OS_Error    Open(int theType);
		void		Close();
        
        enum
        {
            kPortBufSizeInBytes = 8,    //UInt32
            kMaxIPAddrSizeInByt2es = 20  //UInt32
        };


		

		int fFileDesc;



        UInt32          fState;
		Bool m_bIsBlocking;

        

        
        //address information (available if bound)
        //these are always stored in network order. Conver
        struct sockaddr_in  fLocalAddr;
        struct sockaddr_in  fDestAddr;
        
 //       StrPtrLen* fLocalAddrStrPtr;
 //       StrPtrLen* fLocalDNSStrPtr;
        char fPortBuffer[kPortBufSizeInBytes];
        StrPtrLen fPortStr;
        
        //State flags. Be careful when changing these values, as subclasses add their own
        enum
        {
            kBound      = 0x0004,
            kConnected  = 0x0008
        };
                
};

#endif // __SOCKET_H__

